{% extends "console/layout.html" %}
{% block title %}{{ page_title }} · {{site_name|default('RustPBX')}}{% endblock %}
{% block content %}
<div class="p-6">
    <div class="mx-auto max-w-5xl space-y-6" x-data='routingForm({
            mode: {{ mode | tojson }},
            route: {{ route_data | tojson }},
            trunks: {{ trunk_options | tojson }},
            algorithms: {{ selection_algorithms | tojson }},
            directionOptions: {{ direction_options | tojson }},
            statusOptions: {{ status_options | tojson }},
            formAction: {{ form_action | tojson }},
            listUrl: {{ back_url | tojson }}
    })'>
        <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
            <div>
                <nav class="text-xs font-medium text-slate-400">
                    <a href="{{ back_url }}" class="hover:text-slate-600">Routing</a>
                    <span class="mx-1">/</span>
                    <span class="text-slate-600" x-text="mode === 'edit' ? 'Edit rule' : 'Create rule'"></span>
                </nav>
                <h1 class="text-2xl font-semibold text-slate-900"
                    x-text="mode === 'edit' ? 'Edit routing rule' : 'Create routing rule'"></h1>
                <p class="mt-2 text-sm text-slate-500">Define match expressions, rewrite rules, and trunk strategy
                    for this route.</p>
            </div>
            <div class="flex gap-3">
                <a href="{{ back_url }}"
                    class="inline-flex items-center gap-2 rounded-lg border border-slate-200 px-4 py-2 text-sm font-semibold text-slate-600 transition hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-sky-400 focus:ring-offset-2">
                    Cancel
                </a>
                <button type="submit" form="routing-form"
                    class="inline-flex items-center gap-2 rounded-lg bg-sky-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition hover:bg-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-400 focus:ring-offset-2"
                    :class="saving ? 'cursor-not-allowed opacity-80' : ''" :disabled="saving">
                    <svg class="h-4 w-4 animate-spin" viewBox="0 0 20 20" fill="none" stroke="currentColor"
                        stroke-width="1.6" x-show="saving" x-cloak>
                        <path stroke-linecap="round" stroke-linejoin="round"
                            d="M4 10a6 6 0 0 1 6-6m0-3v3m6 6a6 6 0 0 1-6 6m0 3v-3m9-6h-3M1 10h3m10.95 4.95-2.12-2.12M4.05 5.05l2.12 2.12m0 5.66-2.12 2.12m9.9-9.9 2.12-2.12" />
                    </svg>
                    <span x-show="!saving" x-cloak>{{ submit_label }}</span>
                    <span x-show="saving" x-cloak>Saving…</span>
                </button>
            </div>
        </div>

        {% if error_message %}
        <div class="rounded-lg border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700">
            {{ error_message }}
        </div>
        {% endif %}

        <form id="routing-form" class="space-y-6" @submit.prevent="submit">
            <template x-if="error">
                <div class="rounded-lg border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700"
                    x-text="error"></div>
            </template>
            <template x-if="success">
                <div class="rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700"
                    x-text="success"></div>
            </template>

            <div class="rounded-xl bg-white p-3 shadow-sm ring-1 ring-black/5">
                <nav class="inline-flex w-full flex-wrap gap-2 rounded-lg border border-slate-200 bg-slate-50 p-1 text-xs font-semibold text-slate-600"
                    role="tablist" aria-label="Routing configuration tabs">
                    <button type="button" class="flex-1 rounded-md px-4 py-2 text-left transition sm:flex-none"
                        :class="activeTab === 'overview' ? 'bg-white text-sky-700 shadow-sm' : 'text-slate-500 hover:text-slate-700'"
                        :aria-selected="activeTab === 'overview'" aria-controls="routing-tab-overview"
                        @click="activeTab = 'overview'">
                        <div class="flex flex-col">
                            <span class="text-sm">Overview</span>
                            <span class="text-[11px] font-normal text-slate-400">Summary & status</span>
                        </div>
                    </button>
                    <button type="button" class="flex-1 rounded-md px-4 py-2 text-left transition sm:flex-none"
                        :class="activeTab === 'matching' ? 'bg-white text-sky-700 shadow-sm' : 'text-slate-500 hover:text-slate-700'"
                        :aria-selected="activeTab === 'matching'" aria-controls="routing-tab-matching"
                        @click="activeTab = 'matching'">
                        <div class="flex flex-col">
                            <span class="text-sm">Match</span>
                            <span class="text-[11px] font-normal text-slate-400">Patterns applied before routing</span>
                        </div>
                    </button>
                    <button type="button" class="flex-1 rounded-md px-4 py-2 text-left transition sm:flex-none"
                        :class="activeTab === 'rewrite' ? 'bg-white text-sky-700 shadow-sm' : 'text-slate-500 hover:text-slate-700'"
                        :aria-selected="activeTab === 'rewrite'" aria-controls="routing-tab-rewrite"
                        @click="activeTab = 'rewrite'">
                        <div class="flex flex-col">
                            <span class="text-sm">Rewrite</span>
                            <span class="text-[11px] font-normal text-slate-400">Transforms and header updates</span>
                        </div>
                    </button>
                    <button type="button" class="flex-1 rounded-md px-4 py-2 text-left transition sm:flex-none"
                        :class="activeTab === 'delivery' ? 'bg-white text-sky-700 shadow-sm' : 'text-slate-500 hover:text-slate-700'"
                        :aria-selected="activeTab === 'delivery'" aria-controls="routing-tab-delivery"
                        @click="activeTab = 'delivery'">
                        <div class="flex flex-col">
                            <span class="text-sm">Trunks & delivery</span>
                            <span class="text-[11px] font-normal text-slate-400">Selection strategy & weights</span>
                        </div>
                    </button>
                </nav>
            </div>

            <div x-show="activeTab === 'overview'" x-transition.opacity x-cloak class="space-y-6"
                id="routing-tab-overview" role="tabpanel" tabindex="0">
                <section class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-black/5">
                    <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
                        <div>
                            <h2 class="text-base font-semibold text-slate-900">Basics</h2>
                            <p class="text-xs text-slate-500">Set the identity, priority, and rollout status.</p>
                        </div>
                        <div class="flex items-center gap-2 text-xs font-medium text-slate-600">
                            <span class="rounded-full border border-slate-200 px-2 py-1"
                                x-text="route.id ? 'Rule ID: ' + route.id : 'New rule'"></span>
                            <span class="rounded-full border border-slate-200 px-2 py-1" x-text="routeSummary"></span>
                        </div>
                    </div>

                    <div class="mt-6 grid gap-4 md:grid-cols-2">
                        <div class="space-y-2">
                            <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Name</label>
                            <input type="text" name="name" x-model="route.name"
                                class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                placeholder="Outbound Hong Kong" required>
                        </div>
                        <div class="space-y-2">
                            <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Owner</label>
                            <input type="text" name="owner" x-model="route.owner"
                                class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                placeholder="Voice Ops">
                        </div>
                        <div class="space-y-2">
                            <label
                                class="text-xs font-semibold uppercase tracking-wide text-slate-500">Direction</label>
                            <select name="direction" x-model="route.direction"
                                class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200">
                                <template x-for="direction in directionOptions" :key="direction">
                                    <option :value="direction" x-text="direction"></option>
                                </template>
                            </select>
                        </div>
                        <div class="space-y-2">
                            <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Priority</label>
                            <input type="number" min="0" name="priority" x-model.number="route.priority"
                                class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200">
                        </div>
                        <div class="space-y-2">
                            <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Status</label>
                            <div class="flex gap-2">
                                <template x-for="option in statusOptions" :key="option.value">
                                    <button type="button"
                                        class="flex-1 rounded-lg border px-3 py-2 text-xs font-semibold transition"
                                        :class="route.disabled === option.value ? 'border-sky-300 bg-sky-50 text-sky-700' : 'border-slate-200 text-slate-600 hover:bg-slate-50'"
                                        @click="route.disabled = option.value">
                                        <span x-text="option.label"></span>
                                    </button>
                                </template>
                            </div>
                        </div>
                        <div class="space-y-2 md:col-span-2">
                            <label
                                class="text-xs font-semibold uppercase tracking-wide text-slate-500">Description</label>
                            <textarea name="description" x-model="route.description"
                                class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                rows="3"
                                placeholder="Explain what this route handles and key rollout context."></textarea>
                        </div>
                    </div>
                </section>
            </div>

            <div x-show="activeTab === 'matching'" x-transition.opacity x-cloak class="space-y-6"
                id="routing-tab-matching" role="tabpanel" tabindex="0">
                <section class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-black/5">
                    <div class="flex flex-col gap-2">
                        <h2 class="text-base font-semibold text-slate-900">Match expressions</h2>
                        <p class="text-xs text-slate-500">Regular expressions applied to SIP headers before routing
                            takes
                            effect.</p>
                    </div>

                    <div class="mt-6 grid gap-4 md:grid-cols-2">
                        <template x-for="field in matchFields" :key="field.key">
                            <div class="space-y-2">
                                <label class="text-xs font-semibold uppercase tracking-wide text-slate-500"
                                    x-text="field.label"></label>
                                <div class="relative">
                                    <input type="text" :name="'match[' + field.key + ']"
                                        x-model="route.match[field.key]"
                                        class="w-full rounded-lg border border-slate-200 pl-3 pr-16 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                        :placeholder="field.placeholder">

                                    <button type="button" @click.prevent="openRegexPanel(field.key)"
                                        class="absolute right-1 top-1/2 -translate-y-1/2 rounded-md border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">
                                        Regex
                                    </button>

                                    <!-- Regex helper panel -->
                                    <div x-show="regexPanel.open && regexPanel.field === field.key" x-cloak
                                        @click.outside="closeRegexPanel()"
                                        class="absolute z-50 right-0 mt-10 w-[28rem] rounded-lg border border-slate-200 bg-white p-3 shadow-lg">
                                        <div class="flex items-center justify-between gap-2">
                                            <div class="text-sm font-semibold text-slate-700">Regex helper</div>
                                            <div class="text-xs text-slate-400">Presets & tester</div>
                                        </div>
                                        <div class="mt-2 space-y-2">
                                            <div class="rounded-md bg-slate-50 px-2 py-2 text-[11px] text-slate-500">
                                                Use parentheses <code>()</code> to create capture groups so rewrite
                                                rules can reference them with <code>{1}</code>, <code>{2}</code>, and so
                                                on.
                                            </div>
                                            <div class="flex flex-col gap-2">
                                                <input type="text" x-model="regexPanel.builder"
                                                    placeholder="Literal text"
                                                    class="w-full rounded-lg border border-slate-200 px-2 py-1 text-sm text-slate-700 focus:border-sky-300 focus:outline-none">
                                                <div class="flex flex-wrap gap-2">
                                                    <button type="button" @click="buildPreset('starts_with')"
                                                        class="rounded-md border border-slate-200 px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">Start
                                                        With</button>
                                                    <button type="button" @click="buildPreset('ends_with')"
                                                        class="rounded-md border border-slate-200 px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">End
                                                        With</button>
                                                    <button type="button" @click="buildPreset('equals')"
                                                        class="rounded-md border border-slate-200 px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">Equals</button>
                                                </div>
                                            </div>

                                            <div>
                                                <div class="text-xs text-slate-500">Pattern</div>
                                                <input type="text" x-model="regexPanel.pattern"
                                                    class="w-full rounded-lg border border-slate-200 px-2 py-1 text-sm text-slate-700 focus:border-sky-300 focus:outline-none">
                                            </div>

                                            <div class="grid grid-cols-3 gap-2">
                                                <input type="text" x-model="regexPanel.testInput"
                                                    placeholder="Test input"
                                                    class="col-span-2 rounded-lg border border-slate-200 px-2 py-1 text-sm text-slate-700 focus:border-sky-300 focus:outline-none">
                                                <button type="button" @click="testRegex()"
                                                    class="rounded-md border border-slate-200 px-2 py-1 text-sm text-sky-600 hover:bg-slate-50">Test</button>
                                            </div>

                                            <div class="mt-2 space-y-2 text-xs">
                                                <template x-if="regexPanel.error">
                                                    <div class="rounded-md bg-rose-50 px-2 py-1 text-rose-700"
                                                        x-text="regexPanel.error"></div>
                                                </template>
                                                <template x-if="regexPanel.lastMatch === null && !regexPanel.error">
                                                    <div class="rounded-md bg-slate-50 px-2 py-1 text-slate-500">
                                                        Use Test to see whether the pattern matches and which capture
                                                        groups are extracted.
                                                    </div>
                                                </template>
                                                <template x-if="regexPanel.lastMatch !== null">
                                                    <div class="rounded-md border border-slate-200 px-2 py-2 text-sm">
                                                        <div
                                                            class="text-xs font-semibold uppercase tracking-wide text-slate-500">
                                                            Test result
                                                        </div>
                                                        <div class="mt-1 text-sm"
                                                            :class="regexPanel.lastMatch ? 'text-emerald-600' : 'text-rose-600'"
                                                            x-text="regexPanel.lastMatch ? 'Matched' : 'No match'">
                                                        </div>
                                                        <template x-if="regexPanel.groups && regexPanel.groups.length">
                                                            <div class="mt-2">
                                                                <div class="text-xs text-slate-500">Capture groups</div>
                                                                <ul class="mt-1 list-disc pl-5 text-xs text-slate-700">
                                                                    <template x-for="(g, i) in regexPanel.groups"
                                                                        :key="i">
                                                                        <li>
                                                                            <span class="font-mono"
                                                                                x-text="'{' + (i + 1) + '}'"></span>
                                                                            <span class="mx-1">→</span>
                                                                            <span x-text="g"></span>
                                                                        </li>
                                                                    </template>
                                                                </ul>
                                                            </div>
                                                        </template>
                                                        <template
                                                            x-if="regexPanel.lastMatch && (!regexPanel.groups || !regexPanel.groups.length)">
                                                            <div class="mt-2 text-xs text-slate-400">
                                                                No capture groups detected. Wrap parts of your pattern
                                                                in parentheses to populate {1}, {2}, and so on.
                                                            </div>
                                                        </template>
                                                    </div>
                                                </template>
                                            </div>

                                            <div class="mt-3 flex justify-end gap-2">
                                                <button type="button" @click="closeRegexPanel()"
                                                    class="rounded-md border border-slate-200 px-3 py-1 text-xs text-slate-600 hover:bg-slate-50">Cancel</button>
                                                <button type="button" @click="applyRegexPanel()"
                                                    class="rounded-md bg-sky-600 px-3 py-1 text-xs text-white hover:bg-sky-500">Apply</button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </template>
                    </div>

                    <div class="mt-6 space-y-3">
                        <div class="flex items-center justify-between">
                            <h3 class="text-xs font-semibold uppercase tracking-wide text-slate-500">Header matchers
                            </h3>
                            <button type="button" @click="addMatchHeader()"
                                class="inline-flex items-center gap-1 rounded-lg border border-slate-200 px-2 py-1 text-xs font-semibold text-slate-600 hover:bg-slate-50">
                                Add header
                            </button>
                        </div>
                        <template x-if="!matchHeaders.length">
                            <p class="text-xs text-slate-400">No header-based regex. Add one if needed.</p>
                        </template>
                        <div class="space-y-2">
                            <template x-for="(header, index) in matchHeaders" :key="index">
                                <div
                                    class="grid gap-2 rounded-lg border border-slate-200 p-3 md:grid-cols-[1fr_2fr_auto]">
                                    <input type="text" :name="'match_headers[' + index + '][name]'"
                                        x-model="header.name"
                                        class="rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                        placeholder="X-Account-Code">
                                    <div class="relative">
                                        <input type="text" :name="'match_headers[' + index + '][value]'"
                                            x-model="header.value"
                                            class="w-full rounded-lg border border-slate-200 pl-3 pr-16 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                            placeholder="^sales-.*$">
                                        <button type="button" @click.prevent="openRegexPanel('header', index)"
                                            class="absolute right-1 top-1/2 -translate-y-1/2 rounded-md border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">
                                            Regex
                                        </button>
                                        <div x-show="regexPanel.open && regexPanel.field === 'header' && regexPanel.headerIndex === index"
                                            x-cloak @click.outside="closeRegexPanel()"
                                            class="absolute z-50 right-0 mt-10 w-[28rem] rounded-lg border border-slate-200 bg-white p-3 shadow-lg">
                                            <div class="flex items-center justify-between gap-2">
                                                <div class="text-sm font-semibold text-slate-700">Regex helper</div>
                                                <div class="text-xs text-slate-400">Presets & tester</div>
                                            </div>
                                            <div class="mt-2 space-y-2">
                                                <div
                                                    class="rounded-md bg-slate-50 px-2 py-2 text-[11px] text-slate-500">
                                                    Use parentheses <code>()</code> to create capture groups so rewrite
                                                    rules can reference them with <code>{1}</code>, <code>{2}</code>,
                                                    and so on.
                                                </div>
                                                <div class="flex flex-col gap-2">
                                                    <input type="text" x-model="regexPanel.builder"
                                                        placeholder="Literal text"
                                                        class="w-full rounded-lg border border-slate-200 px-2 py-1 text-sm text-slate-700 focus:border-sky-300 focus:outline-none">
                                                    <div class="flex flex-wrap gap-2">
                                                        <button type="button" @click="buildPreset('starts_with')"
                                                            class="rounded-md border border-slate-200 px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">Start
                                                            With</button>
                                                        <button type="button" @click="buildPreset('ends_with')"
                                                            class="rounded-md border border-slate-200 px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">End
                                                            With</button>
                                                        <button type="button" @click="buildPreset('equals')"
                                                            class="rounded-md border border-slate-200 px-2 py-1 text-xs text-slate-600 hover:bg-slate-50">Equals</button>
                                                    </div>
                                                </div>
                                                <div>
                                                    <div class="text-xs text-slate-500">Pattern</div>
                                                    <input type="text" x-model="regexPanel.pattern"
                                                        class="w-full rounded-lg border border-slate-200 px-2 py-1 text-sm text-slate-700 focus:border-sky-300 focus:outline-none">
                                                </div>
                                                <div class="grid grid-cols-3 gap-2">
                                                    <input type="text" x-model="regexPanel.testInput"
                                                        placeholder="Test input"
                                                        class="col-span-2 rounded-lg border border-slate-200 px-2 py-1 text-sm text-slate-700 focus:border-sky-300 focus:outline-none">
                                                    <button type="button" @click="testRegex()"
                                                        class="rounded-md border border-slate-200 px-2 py-1 text-sm text-sky-600 hover:bg-slate-50">Test</button>
                                                </div>
                                                <div class="mt-2 space-y-2 text-xs">
                                                    <template x-if="regexPanel.error">
                                                        <div class="rounded-md bg-rose-50 px-2 py-1 text-rose-700"
                                                            x-text="regexPanel.error"></div>
                                                    </template>
                                                    <template x-if="regexPanel.lastMatch === null && !regexPanel.error">
                                                        <div class="rounded-md bg-slate-50 px-2 py-1 text-slate-500">
                                                            Use Test to see whether the pattern matches and which
                                                            capture groups are extracted.
                                                        </div>
                                                    </template>
                                                    <template x-if="regexPanel.lastMatch !== null">
                                                        <div
                                                            class="rounded-md border border-slate-200 px-2 py-2 text-sm">
                                                            <div
                                                                class="text-xs font-semibold uppercase tracking-wide text-slate-500">
                                                                Test result
                                                            </div>
                                                            <div class="mt-1 text-sm"
                                                                :class="regexPanel.lastMatch ? 'text-emerald-600' : 'text-rose-600'"
                                                                x-text="regexPanel.lastMatch ? 'Matched' : 'No match'">
                                                            </div>
                                                            <template
                                                                x-if="regexPanel.groups && regexPanel.groups.length">
                                                                <div class="mt-2">
                                                                    <div class="text-xs text-slate-500">Capture groups
                                                                    </div>
                                                                    <ul
                                                                        class="mt-1 list-disc pl-5 text-xs text-slate-700">
                                                                        <template x-for="(g, i) in regexPanel.groups"
                                                                            :key="i">
                                                                            <li>
                                                                                <span class="font-mono"
                                                                                    x-text="'{' + (i + 1) + '}'"></span>
                                                                                <span class="mx-1">→</span>
                                                                                <span x-text="g"></span>
                                                                            </li>
                                                                        </template>
                                                                    </ul>
                                                                </div>
                                                            </template>
                                                            <template
                                                                x-if="regexPanel.lastMatch && (!regexPanel.groups || !regexPanel.groups.length)">
                                                                <div class="mt-2 text-xs text-slate-400">
                                                                    No capture groups detected. Wrap parts of your
                                                                    pattern in parentheses to populate {1}, {2}, and so
                                                                    on.
                                                                </div>
                                                            </template>
                                                        </div>
                                                    </template>
                                                </div>
                                                <div class="mt-3 flex justify-end gap-2">
                                                    <button type="button" @click="closeRegexPanel()"
                                                        class="rounded-md border border-slate-200 px-3 py-1 text-xs text-slate-600 hover:bg-slate-50">Cancel</button>
                                                    <button type="button" @click="applyRegexPanel()"
                                                        class="rounded-md bg-sky-600 px-3 py-1 text-xs text-white hover:bg-sky-500">Apply</button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <button type="button" @click="removeMatchHeader(index)"
                                        class="rounded-lg border border-slate-200 px-3 py-2 text-xs font-semibold text-slate-500 hover:bg-slate-50">
                                        Remove
                                    </button>
                                </div>
                            </template>
                        </div>
                    </div>
                </section>

            </div>

            <div x-show="activeTab === 'rewrite'" x-transition.opacity x-cloak class="space-y-6"
                id="routing-tab-rewrite" role="tabpanel" tabindex="0">
                <section class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-black/5">
                    <div class="flex flex-col gap-2">
                        <h2 class="text-base font-semibold text-slate-900">Rewrite rules</h2>
                        <p class="text-xs text-slate-500">Rewrite portions of the SIP request before it reaches the
                            destination.</p>
                    </div>

                    <div class="mt-6 grid gap-4 md:grid-cols-2">
                        <template x-for="field in rewriteFields" :key="field.key">
                            <div class="space-y-2">
                                <label class="text-xs font-semibold uppercase tracking-wide text-slate-500"
                                    x-text="field.label"></label>
                                <div class="text-[11px] text-slate-400">
                                    Matching regex:
                                    <code class="font-mono text-[11px]"
                                        x-text="trimString(route.match[field.key] || '') || '—'"></code>
                                </div>
                                <input type="text" :name="'rewrite[' + field.key + ']'"
                                    x-model="route.rewrite[field.key]"
                                    class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                    :placeholder="field.placeholder">
                            </div>
                        </template>
                    </div>

                    <div class="mt-6 space-y-3">
                        <div class="flex items-center justify-between">
                            <h3 class="text-xs font-semibold uppercase tracking-wide text-slate-500">Set headers</h3>
                            <button type="button" @click="addRewriteHeader()"
                                class="inline-flex items-center gap-1 rounded-lg border border-slate-200 px-2 py-1 text-xs font-semibold text-slate-600 hover:bg-slate-50">
                                Add header
                            </button>
                        </div>
                        <template x-if="!rewriteHeaders.length">
                            <p class="text-xs text-slate-400">No header rewrites defined.</p>
                        </template>
                        <div class="space-y-2">
                            <template x-for="(header, index) in rewriteHeaders" :key="index">
                                <div
                                    class="grid gap-2 rounded-lg border border-slate-200 p-3 md:grid-cols-[1fr_2fr_auto]">
                                    <input type="text" :name="'rewrite_headers[' + index + '][name]'"
                                        x-model="header.name"
                                        class="rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                        placeholder="X-Account-Code">
                                    <input type="text" :name="'rewrite_headers[' + index + '][value]'"
                                        x-model="header.value"
                                        class="rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                        placeholder="sales-apac">
                                    <button type="button" @click="removeRewriteHeader(index)"
                                        class="rounded-lg border border-slate-200 px-3 py-2 text-xs font-semibold text-slate-500 hover:bg-slate-50">
                                        Remove
                                    </button>
                                </div>
                            </template>
                        </div>
                    </div>
                </section>
            </div>

            <div x-show="activeTab === 'delivery'" x-transition.opacity x-cloak class="space-y-6"
                id="routing-tab-delivery" role="tabpanel" tabindex="0">
                <section class="rounded-xl bg-white p-6 shadow-sm ring-1 ring-black/5">
                    <div class="flex flex-col gap-2">
                        <h2 class="text-base font-semibold text-slate-900">Action & trunks</h2>
                        <p class="text-xs text-slate-500">Choose how destinations are selected and how weights are
                            distributed across trunks.</p>
                    </div>

                    <div class="mt-6 space-y-6">
                        <div class="space-y-2">
                            <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Selection
                                algorithm</label>
                            <div class="flex flex-wrap gap-2">
                                <template x-for="option in algorithmOptions" :key="option.value">
                                    <button type="button"
                                        class="rounded-lg border px-3 py-2 text-xs font-semibold transition"
                                        :class="route.action.select === option.value ? 'border-sky-300 bg-sky-50 text-sky-700' : 'border-slate-200 text-slate-600 hover:bg-slate-50'"
                                        @click="setAlgorithm(option.value)">
                                        <span x-text="option.label"></span>
                                    </button>
                                </template>
                            </div>
                            <template x-if="route.action.select === 'hash'">
                                <div class="mt-3 space-y-2">
                                    <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Hash
                                        key</label>
                                    <input type="text" name="hash_key" x-model="route.action.hash_key"
                                        class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                        placeholder="caller">
                                </div>
                            </template>
                        </div>

                        <div class="space-y-3">
                            <div class="flex items-center justify-between">
                                <h3 class="text-xs font-semibold uppercase tracking-wide text-slate-500">Trunk pool</h3>
                                <button type="button" @click="addTrunkAssignment()"
                                    class="inline-flex items-center gap-1 rounded-lg border border-slate-200 px-2 py-1 text-xs font-semibold text-slate-600 hover:bg-slate-50">
                                    Add trunk
                                </button>
                            </div>
                            <template x-if="!route.action.trunks.length">
                                <p class="text-xs text-slate-400">No dedicated trunk weights. The default route or
                                    fallback will be used.</p>
                            </template>
                            <div class="space-y-3">
                                <template x-for="(trunk, index) in route.action.trunks" :key="index">
                                    <div
                                        class="grid gap-2 rounded-lg border border-slate-200 p-3 md:grid-cols-[minmax(0,1fr)_120px_auto]">
                                        <select x-model="trunk.name"
                                            class="rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200">
                                            <option value="">Select trunk</option>
                                            <template x-for="option in trunkOptions" :key="option.name">
                                                <option :value="option.name"
                                                    x-text="option.display_name || option.name">
                                                </option>
                                            </template>
                                        </select>
                                        <input type="number" min="0" step="1" x-model.number="trunk.weight"
                                            class="rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                                            placeholder="Weight">
                                        <button type="button" @click="removeTrunkAssignment(index)"
                                            class="rounded-lg border border-slate-200 px-3 py-2 text-xs font-semibold text-slate-500 hover:bg-slate-50">
                                            Remove
                                        </button>
                                    </div>
                                </template>
                            </div>
                            <div class="rounded-lg bg-slate-50 p-3 text-xs text-slate-500">
                                <div class="flex flex-wrap items-center gap-3">
                                    <span>Total weight:</span>
                                    <span class="rounded-full bg-white px-2 py-1 font-semibold text-slate-700"
                                        x-text="totalWeight"></span>
                                    <span>Normalized distribution preview:</span>
                                    <div class="flex flex-wrap gap-2 text-[11px]">
                                        <template x-for="item in normalizedWeights" :key="item.name">
                                            <span
                                                class="inline-flex items-center gap-1 rounded-full bg-white px-2 py-1 font-semibold text-slate-600">
                                                <span x-text="item.label"></span>
                                                <span class="text-slate-400" x-text="item.percent + '%' "></span>
                                            </span>
                                        </template>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div class="grid gap-4 md:grid-cols-2">
                            <div class="space-y-2">
                                <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Source
                                    trunk (optional)</label>
                                <select name="source_trunk" x-model="route.source_trunk"
                                    class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-800 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200">
                                    <option value="">Select source trunk</option>
                                    <template x-for="option in trunkOptions" :key="'source-' + option.name">
                                        <option :value="option.name" x-text="option.display_name || option.name">
                                        </option>
                                    </template>
                                </select>
                            </div>
                            <div class="space-y-2">
                                <label class="text-xs font-semibold uppercase tracking-wide text-slate-500">Target
                                    trunks (optional)</label>
                                <div class="rounded-lg border border-slate-200 p-3 text-xs text-slate-600">
                                    <template x-for="option in trunkOptions" :key="'target-' + option.name">
                                        <label class="mb-2 flex items-center gap-2">
                                            <input type="checkbox" :value="option.name"
                                                @change="toggleTarget(option.name)"
                                                :checked="route.target_trunks.includes(option.name)"
                                                class="h-4 w-4 rounded border-slate-300 text-sky-600 focus:ring-sky-500">
                                            <span x-text="option.display_name || option.name"></span>
                                        </label>
                                    </template>
                                    <template x-if="!trunkOptions.length">
                                        <p class="text-slate-400">No trunks available. Add trunks first.</p>
                                    </template>
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            </div>
        </form>
    </div>
</div>

<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data('routingForm', (options = {}) => ({
            mode: options.mode || 'create',
            activeTab: 'overview',
            listUrl: options.listUrl || '/console/routing',
            formAction: options.formAction || options.listUrl || '/console/routing',
            directionOptions: Array.isArray(options.directionOptions) ? options.directionOptions : [],
            statusOptions: Array.isArray(options.statusOptions) ? options.statusOptions : [],
            trunkOptions: [],
            algorithmOptions: [],
            route: {
                id: null,
                name: '',
                description: '',
                owner: '',
                direction: 'outbound',
                priority: 10,
                disabled: false,
                match: {},
                rewrite: {},
                action: { select: 'rr', hash_key: null, trunks: [] },
                source_trunk: '',
                target_trunks: [],
            },
            matchHeaders: [],
            rewriteHeaders: [],
            // Regex helper panel state
            regexPanel: {
                open: false,
                field: null,
                headerIndex: null,
                builder: '',
                pattern: '',
                testInput: '',
                groups: [],
                lastMatch: null,
                error: null,
            },
            saving: false,
            error: null,
            success: null,
            init() {
                this.listUrl = (this.listUrl || '').replace(/\/$/, '') || '/console/routing';
                this.formAction = (this.formAction || this.listUrl || '/console/routing').replace(/\/$/, '');
                this.algorithmOptions = Array.isArray(options.algorithms) ? options.algorithms : [];
                this.directionOptions = (Array.isArray(options.directionOptions) ? options.directionOptions : [])
                    .map((value) => this.trimString(value))
                    .filter((value) => value.length);
                this.statusOptions = Array.isArray(options.statusOptions) ? options.statusOptions : [];
                const trunksData = options.trunks;
                this.trunkOptions = Array.isArray(trunksData) ? trunksData : (trunksData?.trunks || []);
                const normalised = this.normaliseRoute(options.route || {});
                this.route = normalised.route;
                this.matchHeaders = normalised.matchHeaders;
                this.rewriteHeaders = normalised.rewriteHeaders;
            },
            // Regex helper methods
            openRegexPanel(field, headerIndex = null) {
                this.regexPanel.open = true;
                this.regexPanel.field = field;
                this.regexPanel.headerIndex = headerIndex;
                this.regexPanel.builder = '';
                this.regexPanel.testInput = '';
                this.regexPanel.groups = [];
                this.regexPanel.lastMatch = null;
                this.regexPanel.error = null;

                // Load stored value into the helper state
                let stored = '';
                if (headerIndex === null) {
                    stored = this.trimString(this.route.match[field] || '');
                } else {
                    stored = this.trimString((this.matchHeaders[headerIndex] && this.matchHeaders[headerIndex].value) || '');
                }
                this.regexPanel.pattern = stored;
            },
            closeRegexPanel() {
                this.regexPanel.open = false;
                this.regexPanel.field = null;
                this.regexPanel.headerIndex = null;
                this.regexPanel.builder = '';
                this.regexPanel.pattern = '';
                this.regexPanel.testInput = '';
                this.regexPanel.groups = [];
                this.regexPanel.lastMatch = null;
                this.regexPanel.error = null;
            },
            buildPreset(type) {
                const raw = this.trimString(this.regexPanel.builder || '');
                const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
                const lit = escapeRegExp(raw);
                if (!raw.length) return;
                switch (type) {
                    case 'starts_with':
                        this.regexPanel.pattern = `^${lit}(.*)$`;
                        break;
                    case 'ends_with':
                        this.regexPanel.pattern = `^(.*)${lit}$`;
                        break;
                    case 'equals':
                        this.regexPanel.pattern = `^(${lit})$`;
                        break;
                }
            },
            testRegex() {
                this.regexPanel.error = null;
                this.regexPanel.groups = [];
                this.regexPanel.lastMatch = null;
                const rawPattern = this.regexPanel.pattern || '';
                if (!rawPattern.length) {
                    this.regexPanel.error = 'Empty pattern';
                    return;
                }
                const input = String(this.regexPanel.testInput ?? '');
                if (!input.length) {
                    this.regexPanel.error = 'Enter test input before running the test.';
                    return;
                }
                try {
                    const re = new RegExp(rawPattern);
                    const m = re.exec(input);
                    if (m) {
                        this.regexPanel.groups = m.slice(1).map((g) => g == null ? '' : g);
                        this.regexPanel.lastMatch = true;
                    } else {
                        this.regexPanel.groups = [];
                        this.regexPanel.lastMatch = false;
                    }
                } catch (err) {
                    this.regexPanel.error = 'Invalid regex: ' + (err && err.message ? err.message : err);
                }
            },
            applyRegexPanel() {
                const raw = this.regexPanel.pattern || '';
                if (this.regexPanel.headerIndex === null) {
                    this.route.match[this.regexPanel.field] = raw;
                } else {
                    const idx = this.regexPanel.headerIndex;
                    if (this.matchHeaders[idx]) {
                        this.matchHeaders[idx].value = raw;
                    }
                }
                this.closeRegexPanel();
            },
            normaliseRoute(raw) {
                const toBoolean = (value) => {
                    if (typeof value === 'boolean') return value;
                    if (typeof value === 'string') {
                        const trimmed = value.trim().toLowerCase();
                        if (['true', '1', 'yes', 'enabled'].includes(trimmed)) return true;
                        if (['false', '0', 'no', 'disabled'].includes(trimmed)) return false;
                    }
                    return Boolean(value);
                };
                const normalizeDirection = (value) => {
                    if (typeof value === 'string' && value.trim().length) {
                        return value.trim().toLowerCase();
                    }
                    return 'outbound';
                };
                const normalizeSelection = (value) => {
                    if (typeof value === 'string' && value.trim().length) {
                        return value.trim().toLowerCase();
                    }
                    return 'rr';
                };
                const route = {
                    id: raw?.id ?? null,
                    name: raw?.name ?? '',
                    description: raw?.description ?? '',
                    owner: raw?.owner ?? '',
                    direction: normalizeDirection(raw?.direction),
                    priority: typeof raw?.priority === 'number' ? raw.priority : Number(raw?.priority) || 10,
                    disabled: toBoolean(raw?.disabled),
                    match: Object.assign({
                        from_user: '',
                        from_host: '',
                        to_user: '',
                        to_host: '',
                        request_uri_user: '',
                        request_uri_host: '',
                        request_uri_port: '',
                    }, raw?.match || {}),
                    rewrite: Object.assign({
                        from_user: '',
                        from_host: '',
                        to_user: '',
                        to_host: '',
                        request_uri_user: '',
                        request_uri_host: '',
                    }, raw?.rewrite || {}),
                    action: {
                        select: normalizeSelection(raw?.action?.select),
                        hash_key: raw?.action?.hash_key || null,
                        trunks: Array.isArray(raw?.action?.trunks)
                            ? raw.action.trunks.map((item) => ({
                                name: item?.name || '',
                                weight: typeof item?.weight === 'number' ? item.weight : Number(item?.weight) || 0,
                            }))
                            : [],
                    },
                    source_trunk: raw?.source_trunk || '',
                    target_trunks: Array.isArray(raw?.target_trunks) ? raw.target_trunks.slice() : [],
                };

                const matchHeaders = [];
                Object.keys(route.match).forEach((key) => {
                    if (key.startsWith('header.')) {
                        matchHeaders.push({
                            name: key.replace(/^header\./, ''),
                            value: route.match[key] || '',
                        });
                        delete route.match[key];
                    }
                });

                const rewriteHeaders = [];
                Object.keys(route.rewrite).forEach((key) => {
                    if (key.startsWith('header.')) {
                        rewriteHeaders.push({
                            name: key.replace(/^header\./, ''),
                            value: route.rewrite[key] || '',
                        });
                        delete route.rewrite[key];
                    }
                });

                return { route, matchHeaders, rewriteHeaders };
            },
            trimString(value) {
                if (value == null) return '';
                return typeof value === 'string' ? value.trim() : String(value).trim();
            },
            sanitizeKeyValue(object) {
                const result = {};
                Object.entries(object || {}).forEach(([key, value]) => {
                    const trimmedValue = this.trimString(value);
                    if (trimmedValue.length) {
                        result[key] = trimmedValue;
                    }
                });
                return result;
            },
            get matchFields() {
                return [
                    { key: 'from_user', label: 'From user regex', placeholder: '^20(0[1-9]|[1-9][0-9])$' },
                    { key: 'from_host', label: 'From host regex', placeholder: '^sip\\.example\\.com$' },
                    { key: 'to_user', label: 'To user regex', placeholder: '^(852|853)\\d{7,8}$' },
                    { key: 'to_host', label: 'To host regex', placeholder: '^carrier\\.provider\\.net$' },
                    { key: 'request_uri_user', label: 'Request-URI user regex', placeholder: '^(400|800)\\d{6}$' },
                    { key: 'request_uri_host', label: 'Request-URI host regex', placeholder: '.*' },
                    { key: 'request_uri_port', label: 'Request-URI port', placeholder: '5061' },
                ];
            },
            get rewriteFields() {
                return [
                    { key: 'from_user', label: 'Rewrite From user', placeholder: '{1}' },
                    { key: 'from_host', label: 'Rewrite From host', placeholder: 'sip.internal' },
                    { key: 'to_user', label: 'Rewrite To user', placeholder: '00{1}' },
                    { key: 'to_host', label: 'Rewrite To host', placeholder: 'carrier.provider.net' },
                    { key: 'request_uri_user', label: 'Rewrite Request-URI user', placeholder: 'ivr-{1}' },
                    { key: 'request_uri_host', label: 'Rewrite Request-URI host', placeholder: 'rtp.provider.net' },
                ];
            },
            addMatchHeader() {
                this.matchHeaders.push({ name: '', value: '' });
            },
            removeMatchHeader(index) {
                this.matchHeaders.splice(index, 1);
            },
            addRewriteHeader() {
                this.rewriteHeaders.push({ name: '', value: '' });
            },
            removeRewriteHeader(index) {
                this.rewriteHeaders.splice(index, 1);
            },
            addTrunkAssignment() {
                this.route.action.trunks.push({ name: '', weight: 0 });
            },
            removeTrunkAssignment(index) {
                this.route.action.trunks.splice(index, 1);
            },
            setAlgorithm(value) {
                if (typeof value === 'string' && value.trim().length) {
                    this.route.action.select = value.trim().toLowerCase();
                } else {
                    this.route.action.select = 'rr';
                }
                if (this.route.action.select !== 'hash') {
                    this.route.action.hash_key = null;
                }
            },
            toggleTarget(name) {
                const candidate = this.trimString(name);
                if (!candidate.length) return;
                const current = new Set(
                    (this.route.target_trunks || [])
                        .map((value) => this.trimString(value))
                        .filter((value) => value.length),
                );
                if (current.has(candidate)) {
                    current.delete(candidate);
                } else {
                    current.add(candidate);
                }
                this.route.target_trunks = Array.from(current);
            },
            get totalWeight() {
                return this.route.action.trunks.reduce((sum, trunk) => sum + (Number(trunk.weight) || 0), 0);
            },
            get normalizedWeights() {
                const total = this.totalWeight || 1;
                return this.route.action.trunks
                    .map((trunk) => ({
                        name: this.trimString(trunk.name),
                        label: this.trimString(trunk.name) || '—',
                        percent: Math.round(((Number(trunk.weight) || 0) / total) * 100),
                    }))
                    .filter((item) => item.name.length);
            },
            get routeSummary() {
                return `${this.route.direction} · priority ${this.route.priority}`;
            },
            submitUrl() {
                return this.formAction || this.listUrl;
            },
            submitMethod() {
                return this.mode === 'edit' ? 'PATCH' : 'PUT';
            },
            validate() {
                const name = this.trimString(this.route.name);
                if (!name.length) {
                    throw new Error('Route name is required.');
                }
                const source = this.trimString(this.route.source_trunk);
                if (source.length) {
                    const exists = this.trunkOptions.some((option) => {
                        const candidate = this.trimString(option?.name);
                        return candidate.length && candidate.toLowerCase() === source.toLowerCase();
                    });
                    if (!exists) {
                        throw new Error(`Source trunk "${source}" is not available.`);
                    }
                }
            },
            buildPayload() {
                const match = this.sanitizeKeyValue(this.route.match);
                this.matchHeaders.forEach((header) => {
                    const name = this.trimString(header.name);
                    const value = this.trimString(header.value);
                    if (name.length && value.length) {
                        match[`header.${name}`] = value;
                    }
                });

                const rewrite = this.sanitizeKeyValue(this.route.rewrite);
                this.rewriteHeaders.forEach((header) => {
                    const name = this.trimString(header.name);
                    const value = this.trimString(header.value);
                    if (name.length && value.length) {
                        rewrite[`header.${name}`] = value;
                    }
                });

                const trunks = this.route.action.trunks
                    .map((trunk) => ({
                        name: this.trimString(trunk.name),
                        weight: Math.max(0, Math.round(Number(trunk.weight) || 0)),
                    }))
                    .filter((trunk) => trunk.name.length);

                const hashKey = this.route.action.select === 'hash'
                    ? this.trimString(this.route.action.hash_key)
                    : '';

                const targetTrunks = Array.from(
                    new Set(
                        (this.route.target_trunks || [])
                            .map((name) => this.trimString(name))
                            .filter((name) => name.length),
                    ),
                );

                const description = this.trimString(this.route.description);
                const owner = this.trimString(this.route.owner);

                return {
                    id: this.route.id,
                    name: this.trimString(this.route.name),
                    description: description || null,
                    owner: owner || null,
                    direction: this.route.direction || 'outbound',
                    priority: Math.max(0, Math.round(Number(this.route.priority) || 0)),
                    disabled: Boolean(this.route.disabled),
                    match,
                    rewrite,
                    action: {
                        select: this.route.action.select || 'rr',
                        hash_key: hashKey.length ? hashKey : null,
                        trunks,
                    },
                    source_trunk: this.trimString(this.route.source_trunk) || null,
                    target_trunks: targetTrunks,
                };
            },
            async submit() {
                try {
                    this.validate();
                } catch (err) {
                    this.error = err?.message || 'Validation failed.';
                    this.success = null;
                    return;
                }
                this.saving = true;
                this.error = null;
                this.success = null;
                const payload = this.buildPayload();
                try {
                    const response = await fetch(this.submitUrl(), {
                        method: this.submitMethod(),
                        headers: {
                            'Accept': 'application/json',
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(payload),
                    });
                    const data = await response.json().catch(() => ({}));
                    if (!response.ok) {
                        throw new Error(data?.message || 'Failed to save routing rule');
                    }
                    if (this.mode === 'create' && data?.id) {
                        window.location.href = `${this.listUrl}/${data.id}`;
                        return;
                    }
                    this.mode = 'edit';
                    this.success = 'Changes saved successfully.';
                } catch (err) {
                    console.error(err);
                    this.error = err?.message || 'Failed to save routing rule';
                } finally {
                    this.saving = false;
                }
            },
        }));
    });
</script>
{% endblock %}